package com.xjiye_test.payServer.serverletUtil;

import com.xjiye_test.payServer.serverletUtil.codec.Base64;
import org.apache.commons.lang.StringUtils;

import javax.crypto.Cipher;
import java.io.*;
import java.net.URLDecoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class PaySignature {

    /** RSA最大加密明文大小  */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** RSA最大解密密文大小   */
    private static final int MAX_DECRYPT_BLOCK = 128;

    public static void main(String[] args) throws PlatformPayException, UnsupportedEncodingException {
//		Map<String, String> p = new HashMap<String, String>();
//		p.put("amount", "1");
//		p.put("subject", "test");
//		p.put("order_no", "t123");
//		p.put("auth_code", "130095740823139018");
//		p.put("s_id", "20033");
//		p.put("pay_type", "PAY_KEY");
//		p.put("pay_channel", "Alipay");
//		String cont = getSignCheckContent(p);
//		String pkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLlxjBvrGupn4jumnZ1F4yj+/MsNVHxLax6MdsdFSdrwWstu6g2Ap6LNe8PjzVPy0SFBHu41FbcqEO58zorBen0qlHuRwczFWp+Pe8BeBZo+05vAusnyQBXOCpnu+Tgj5es3FfoOqyvT+Eg3hWs+swMBDQXmUWBonAYH1Yqf5V/wIDAQAB";
//		String cKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIVWfiVK+kOHxJbaiV6/Wt/0K0PPRnihaqCxEOc8o7rm3yTBHhYUmb7Fl0VhM8VtF/SxW7dHesu7oLGTm6ovPOoqB08dPkBAML3aRnbKyDo65bnDbCosHKQCdbt1yKc1xSywo+wBc5t8tnh8FxM20PuTC3+SHOIxR5F4fQRL7L/BAgMBAAECgYEAg+2MasHA1UhkTw5zlPeopqYkmLdhdsHfipcnrmPlbGw6pVceuaIwbP18Kv1+B/1lEorZwIJNEX/YA1uVTdHnZilWjRIbUms2GNNbYORH0jMZOxU/J8IwsLiCi8sJA6AqGlnHYZSbcv22vf3T/z15NKfBOfU15Cjzj4NKFouGcPECQQDQpnTmMfHoXYwq+b6mW5ydTBSwNxnmJ4FJVph0vJ/zLX0++qiHNji3aWR6vRo3vqi/Up2uv6IZRlWLmfNlhoOzAkEAo5jC73ZooFaxGkWs2j9k5VwwxlsWDDieOcObSJigqBA+0VYndoZQTjl3SSYPmraYv8URHJQO4B5ybVy//hVEuwJAbLrRoEPWtChLqvmKiFalPrMu9MVCEdX0Yatmty60i5zg77jfqdZvp+ScH/n7d6E7frgmw7HJXzJv0dfgJr/6UQJBAKIAajk7ZkwwzNwZVxwgXseJzXr/RAwCHR1SiHkROzZyL+KYkCecxfVQjsFPAXDRlN2CRnmoXDqvq9yEVlNDuHUCQFWYZILxMwY1jwHKPTnf85nGUFHqCWWi3LG9a+HO/S6oQah3UNqdd3qdCTlDCkXlsLtEVp5NWmfgArvj9Wtx+kg=";
//
//		 String encrypted = rsaEncrypt(cont, pkey, "UTF-8");
//		 String sign = rsaSign(encrypted, cKey, "UTF-8");
//		 System.out.println(URLEncoder.encode(encrypted, "UTF-8"));
//		 System.out.println();
//		 System.out.println(URLEncoder.encode(sign, "UTF-8"));
//
        String cPrivatekey ="MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIVWfiVK+kOHxJbaiV6/Wt/0K0PPRnihaqCxEOc8o7rm3yTBHhYUmb7Fl0VhM8VtF/SxW7dHesu7oLGTm6ovPOoqB08dPkBAML3aRnbKyDo65bnDbCosHKQCdbt1yKc1xSywo+wBc5t8tnh8FxM20PuTC3+SHOIxR5F4fQRL7L/BAgMBAAECgYEAg+2MasHA1UhkTw5zlPeopqYkmLdhdsHfipcnrmPlbGw6pVceuaIwbP18Kv1+B/1lEorZwIJNEX/YA1uVTdHnZilWjRIbUms2GNNbYORH0jMZOxU/J8IwsLiCi8sJA6AqGlnHYZSbcv22vf3T/z15NKfBOfU15Cjzj4NKFouGcPECQQDQpnTmMfHoXYwq+b6mW5ydTBSwNxnmJ4FJVph0vJ/zLX0++qiHNji3aWR6vRo3vqi/Up2uv6IZRlWLmfNlhoOzAkEAo5jC73ZooFaxGkWs2j9k5VwwxlsWDDieOcObSJigqBA+0VYndoZQTjl3SSYPmraYv8URHJQO4B5ybVy//hVEuwJAbLrRoEPWtChLqvmKiFalPrMu9MVCEdX0Yatmty60i5zg77jfqdZvp+ScH/n7d6E7frgmw7HJXzJv0dfgJr/6UQJBAKIAajk7ZkwwzNwZVxwgXseJzXr/RAwCHR1SiHkROzZyL+KYkCecxfVQjsFPAXDRlN2CRnmoXDqvq9yEVlNDuHUCQFWYZILxMwY1jwHKPTnf85nGUFHqCWWi3LG9a+HO/S6oQah3UNqdd3qdCTlDCkXlsLtEVp5NWmfgArvj9Wtx+kg=";
        String pPulibcKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLlxjBvrGupn4jumnZ1F4yj+/MsNVHxLax6MdsdFSdrwWstu6g2Ap6LNe8PjzVPy0SFBHu41FbcqEO58zorBen0qlHuRwczFWp+Pe8BeBZo+05vAusnyQBXOCpnu+Tgj5es3FfoOqyvT+Eg3hWs+swMBDQXmUWBonAYH1Yqf5V/wIDAQAB";
        String bizC = "TUPEpQT%2BIIP6HVI49mExCun1cfU7gR%2F4bYgMtqnGAUxch4Qfpm5rTxtcqHObX712ZV3lXgsmJbtOLQs8xtfpW%2BcyhdWbouEtr1MRR8TZGw7MYoBHa06GT4XShnHXfxbPlhnzEwm74e5yj6WhBX86%2BSLf45c%2BuFhAdOOTicTOTP1wAdO3n5PonZSKYAi1ITh8bqfRBP%2FlHvtaFGyV6KqZ4SiBi203My82Vg4dnDkTmozktqQ68qOoe6i8NY0ebtNn4Q9QqH7RTXcyVbraZ%2BGFe0rfNKtT3yPiA%2BtO%2BSxFb%2BDVf0T6rm5lGD2%2BMQpCxmtnBz5pZ4zowe5neUN4VuWzDA%3D%3D";
        String sign = "ISpBvqc3gv65xlGjqbfEQu8pws%2FZXnGm3cxNjgRnMRXnyGOCrSizrkjU1QGOGf%2FYTBQLRWbs25%2B4L%2FRrOgBxHG4ZPl%2BNGx%2B1MPF2g%2BF6HcvIFABf6YfIFzcVwP5ZOrS3Jo17vy%2Fx4%2FnC6bEQIqz2gyjVXndyyBx08uC7sk%2BLcu4%3D";
        bizC = 	URLDecoder.decode(bizC, "UTF-8");
        sign = 	URLDecoder.decode(sign, "UTF-8");
//        PayReqData req = new PayReqData();
//        req.setBiz_content(bizC);
//        req.setSign(sign);
        System.out.println(rsaCheck(bizC, sign,pPulibcKey, "UTF-8", "RSA"));
        System.out.println(rsaEncrypt(bizC, cPrivatekey, "UTF-8"));



    }
    /**
     * 获取以key=value&key=value形式的字符串
     * @param sortedParams
     * @return
     */
    public static String getSignContent(Map<String, String> sortedParams) {
        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(sortedParams.keySet());
        Collections.sort(keys);
        int index = 0;
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = sortedParams.get(key);
            if (areNotEmpty(key, value)) {
                content.append((index == 0 ? "" : "&") + key + "=" + value);
                index++;
            }
        }
        return content.toString();
    }
    /**
     * 检查指定的字符串列表是否不为空。
     */
    public static boolean areNotEmpty(String... values) {
        boolean result = true;
        if (values == null || values.length == 0) {
            result = false;
        } else {
            for (String value : values) {
                result &= !StringUtils.isEmpty(value);
            }
        }
        return result;
    }
    /**
     *  rsa内容签名
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     * @throws PlatformPayException
     */
    public static String rsaSign(String content, String privateKey, String charset,
                                 String signType) throws PlatformPayException {

        if (PayConstants.SIGN_TYPE_RSA.equals(signType)) {

            return rsaSign(content, privateKey, charset);
        } else if (PayConstants.SIGN_TYPE_RSA2.equals(signType)) {

            return rsa256Sign(content, privateKey, charset);
        } else {

            throw new PlatformPayException("Sign Type is Not Support : signType=" + signType);
        }

    }

    /**
     * sha256WithRsa 加签
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     * @throws PlatformPayException
     */
    public static String rsa256Sign(String content, String privateKey,
                                    String charset) throws PlatformPayException {

        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(PayConstants.SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(PayConstants.SIGN_SHA256RSA_ALGORITHMS);

            signature.initSign(priKey);

            if (StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            byte[] signed = signature.sign();

            return new String(Base64.encodeBase64(signed));
        } catch (Exception e) {
            throw new PlatformPayException("RSAcontent = " + content + "; charset = " + charset, e);
        }

    }

    /**
     * sha1WithRsa 加签
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     * @throws PlatformPayException
     */
    public static String rsaSign(String content, String privateKey, String charset) throws PlatformPayException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(PayConstants.SIGN_TYPE_RSA, new ByteArrayInputStream(privateKey.getBytes()));

            java.security.Signature signature = java.security.Signature.getInstance(PayConstants.SIGN_ALGORITHMS);

            signature.initSign(priKey);

            if (StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            byte[] signed = signature.sign();

            return new String(Base64.encodeBase64(signed));
        } catch (InvalidKeySpecException ie) {
            throw new PlatformPayException("RSA私钥格式不正确，请检查是否正确配置了PKCS8格式的私钥", ie);
        } catch (Exception e) {
            throw new PlatformPayException("RSAcontent = " + content + "; charset = " + charset, e);
        }
    }

    public static String rsaSign(Map<String, String> params, String privateKey,
                                 String charset) throws PlatformPayException {
        String signContent = getSignContent(params);

        return rsaSign(signContent, privateKey, charset);

    }

    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
        if (ins == null || StringUtils.isEmpty(algorithm)) {
            return null;
        }

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        byte[] encodedKey = StreamUtil.readText(ins).getBytes();

        encodedKey = Base64.decodeBase64(encodedKey);

        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    public static String getSignCheckContentV1(Map<String, String> params) {
        if (params == null) {
            return null;
        }

        params.remove("sign");
        params.remove("sign_type");

        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            content.append((i == 0 ? "" : "&") + key + "=" + value);
        }

        return content.toString();
    }

    public static String getSignCheckContentV2(Map<String, String> params) {
        if (params == null) {
            return null;
        }

        params.remove("sign");

        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            content.append((i == 0 ? "" : "&") + key + "=" + value);
        }

        return content.toString();
    }

    public static boolean rsaCheckV1(Map<String, String> params, String publicKey,
                                     String charset) throws PlatformPayException {
        String sign = params.get("sign");
        String content = getSignCheckContentV1(params);

        return rsaCheckContent(content, sign, publicKey, charset);
    }

    public static boolean rsaCheckV1(Map<String, String> params, String publicKey,
                                     String charset,String signType) throws PlatformPayException {
        String sign = params.get("sign");
        String content = getSignCheckContentV1(params);

        return rsaCheck(content, sign, publicKey, charset,signType);
    }

    public static boolean rsaCheckV2(Map<String, String> params, String publicKey,
                                     String charset) throws PlatformPayException {
        String sign = params.get("sign");
        String content = getSignCheckContentV2(params);

        return rsaCheckContent(content, sign, publicKey, charset);
    }

    public static boolean rsaCheckV2(Map<String, String> params, String publicKey,
                                     String charset,String signType) throws PlatformPayException {
        String sign = params.get("sign");
        String content = getSignCheckContentV2(params);

        return rsaCheck(content, sign, publicKey, charset,signType);
    }

    public static boolean rsaCheck(String content, String sign, String publicKey, String charset,
                                   String signType) throws PlatformPayException {

        if (PayConstants.SIGN_TYPE_RSA.equals(signType)) {

            return rsaCheckContent(content, sign, publicKey, charset);

        } else if (PayConstants.SIGN_TYPE_RSA2.equals(signType)) {

            return rsa256CheckContent(content, sign, publicKey, charset);

        } else {

            throw new PlatformPayException("Sign Type is Not Support : signType=" + signType);
        }

    }

    public static boolean rsa256CheckContent(String content, String sign, String publicKey,
                                             String charset) throws PlatformPayException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(PayConstants.SIGN_SHA256RSA_ALGORITHMS);

            signature.initVerify(pubKey);

            if (StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            return signature.verify(Base64.decodeBase64(sign.getBytes()));
        } catch (Exception e) {
            throw new PlatformPayException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }
    public static boolean rsaCheckContent(String content, String sign, String publicKey,
                                          String charset) throws PlatformPayException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(PayConstants.SIGN_ALGORITHMS);

            signature.initVerify(pubKey);

            if (StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            return signature.verify(Base64.decodeBase64(sign.getBytes()));
        } catch (Exception e) {
            throw new PlatformPayException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }

    public static PublicKey getPublicKeyFromX509(String algorithm,
                                                 InputStream ins) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        StringWriter writer = new StringWriter();
        StreamUtil.io(new InputStreamReader(ins), writer);

        byte[] encodedKey = writer.toString().getBytes();

        encodedKey = Base64.decodeBase64(encodedKey);

        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /**
     * 验签并解密
     * <p>
     * <b>目前适用于公众号</b><br>
     * params参数示例：
     * <br>{
     *    <br>biz_content=M0qGiGz+8kIpxe8aF4geWJdBn0aBTuJRQItLHo9R7o5JGhpic/MIUjvXo2BLB++BbkSq2OsJCEQFDZ0zK5AJYwvBgeRX30gvEj6eXqXRt16/IkB9HzAccEqKmRHrZJ7PjQWE0KfvDAHsJqFIeMvEYk1Zei2QkwSQPlso7K0oheo/iT+HYE8aTATnkqD/ByD9iNDtGg38pCa2xnnns63abKsKoV8h0DfHWgPH62urGY7Pye3r9FCOXA2Ykm8X4/Bl1bWFN/PFCEJHWe/HXj8KJKjWMO6ttsoV0xRGfeyUO8agu6t587Dl5ux5zD/s8Lbg5QXygaOwo3Fz1G8EqmGhi4+soEIQb8DBYanQOS3X+m46tVqBGMw8Oe+hsyIMpsjwF4HaPKMr37zpW3fe7xOMuimbZ0wq53YP/jhQv6XWodjT3mL0H5ACqcsSn727B5ztquzCPiwrqyjUHjJQQefFTzOse8snaWNQTUsQS7aLsHq0FveGpSBYORyA90qPdiTjXIkVP7mAiYiAIWW9pCEC7F3XtViKTZ8FRMM9ySicfuAlf3jtap6v2KPMtQv70X+hlmzO/IXB6W0Ep8DovkF5rB4r/BJYJLw/6AS0LZM9w5JfnAZhfGM2rKzpfNsgpOgEZS1WleG4I2hoQC0nxg9IcP0Hs+nWIPkEUcYNaiXqeBc=,
     *    <br>sign=rlqgA8O+RzHBVYLyHmrbODVSANWPXf3pSrr82OCO/bm3upZiXSYrX5fZr6UBmG6BZRAydEyTIguEW6VRuAKjnaO/sOiR9BsSrOdXbD5Rhos/Xt7/mGUWbTOt/F+3W0/XLuDNmuYg1yIC/6hzkg44kgtdSTsQbOC9gWM7ayB4J4c=,
     *    sign_type=RSA,
     *    <br>charset=UTF-8
     * <br>}
     * </p>
     * @param params
     * @param payPublicKey 支付宝公钥
     * @param cusPrivateKey   商户私钥
     * @param isCheckSign     是否验签
     * @param isDecrypt       是否解密
     * @return 解密后明文，验签失败则异常抛出
     * @throws PlatformPayException
     */
    public static String checkSignAndDecrypt(Map<String, String> params, String payPublicKey,
                                             String cusPrivateKey, boolean isCheckSign,
                                             boolean isDecrypt) throws PlatformPayException {
        String charset = params.get("charset");
        String bizContent = params.get("biz_content");
        if (isCheckSign) {
            if (!rsaCheckV2(params, payPublicKey, charset)) {
                throw new PlatformPayException("rsaCheck failure:rsaParams=" + params);
            }
        }

        if (isDecrypt) {
            return rsaDecrypt(bizContent, cusPrivateKey, charset);
        }

        return bizContent;
    }
    /**
     * 验签并解密
     * @param bizContent 请求参数
     * @param cusPublicKey 商户私钥
     * @param isCheckSign 是否验签
     * @param isDecrypt 是否解密
     * @return
     * @throws PlatformPayException
     * @author xingzhe
     * @date 2017年5月5日 上午9:23:20
     * @version 1.0
     */
    public static String checkSignAndDecrypt(String bizContent,String signType,String sign,String cusPublicKey, boolean isCheckSign, boolean isDecrypt) throws PlatformPayException {
        String charset = "UTF-8";
        if (StringUtils.isBlank(charset)) {
            charset = PayConstants.CHARSET_UTF8;
        }
        if (StringUtils.isBlank(signType)) {
            signType = PayConstants.SIGN_TYPE_RSA;
        }
        if (StringUtils.isBlank(bizContent) || StringUtils.isBlank(sign)) {
            throw new PlatformPayException("支付参数错误：缺少必填参数");
        }
        if (isCheckSign) {
            if (!rsaCheck(bizContent, sign, cusPublicKey, charset, signType)) {
                throw new PlatformPayException("系统错误：验签失败");
            }
        }
        if (isDecrypt) {
            return rsaDecrypt(bizContent,PayConstants.PAY_PRIVATE_KEY, charset);
        }
        return bizContent;
    }

    /**
     * 验签并解密
     * <p>
     * <b>目前适用于公众号</b><br>
     * params参数示例：
     * <br>{
     *    <br>biz_content=M0qGiGz+8kIpxe8aF4geWJdBn0aBTuJRQItLHo9R7o5JGhpic/MIUjvXo2BLB++BbkSq2OsJCEQFDZ0zK5AJYwvBgeRX30gvEj6eXqXRt16/IkB9HzAccEqKmRHrZJ7PjQWE0KfvDAHsJqFIeMvEYk1Zei2QkwSQPlso7K0oheo/iT+HYE8aTATnkqD/ByD9iNDtGg38pCa2xnnns63abKsKoV8h0DfHWgPH62urGY7Pye3r9FCOXA2Ykm8X4/Bl1bWFN/PFCEJHWe/HXj8KJKjWMO6ttsoV0xRGfeyUO8agu6t587Dl5ux5zD/s8Lbg5QXygaOwo3Fz1G8EqmGhi4+soEIQb8DBYanQOS3X+m46tVqBGMw8Oe+hsyIMpsjwF4HaPKMr37zpW3fe7xOMuimbZ0wq53YP/jhQv6XWodjT3mL0H5ACqcsSn727B5ztquzCPiwrqyjUHjJQQefFTzOse8snaWNQTUsQS7aLsHq0FveGpSBYORyA90qPdiTjXIkVP7mAiYiAIWW9pCEC7F3XtViKTZ8FRMM9ySicfuAlf3jtap6v2KPMtQv70X+hlmzO/IXB6W0Ep8DovkF5rB4r/BJYJLw/6AS0LZM9w5JfnAZhfGM2rKzpfNsgpOgEZS1WleG4I2hoQC0nxg9IcP0Hs+nWIPkEUcYNaiXqeBc=,
     *    <br>sign=rlqgA8O+RzHBVYLyHmrbODVSANWPXf3pSrr82OCO/bm3upZiXSYrX5fZr6UBmG6BZRAydEyTIguEW6VRuAKjnaO/sOiR9BsSrOdXbD5Rhos/Xt7/mGUWbTOt/F+3W0/XLuDNmuYg1yIC/6hzkg44kgtdSTsQbOC9gWM7ayB4J4c=,
     *    sign_type=RSA,
     *    <br>charset=UTF-8
     * <br>}
     * </p>
     * @param params
     * @param payPublicKey 支付宝公钥
     * @param cusPrivateKey   商户私钥
     * @param isCheckSign     是否验签
     * @param isDecrypt       是否解密
     * @return 解密后明文，验签失败则异常抛出
     * @throws PlatformPayException
     */
    public static String checkSignAndDecrypt(Map<String, String> params, String payPublicKey,
                                             String cusPrivateKey, boolean isCheckSign,
                                             boolean isDecrypt, String signType) throws PlatformPayException {
        String charset = params.get("charset");
        String bizContent = params.get("biz_content");
        if (isCheckSign) {
            if (!rsaCheckV2(params, payPublicKey, charset,signType)) {
                throw new PlatformPayException("rsaCheck failure:rsaParams=" + params);
            }
        }

        if (isDecrypt) {
            return rsaDecrypt(bizContent, cusPrivateKey, charset);
        }

        return bizContent;
    }

    /**
     * 加密并签名<br>
     * <b>目前适用于公众号</b>
     * @param bizContent      待加密、签名内容
     * @param payPublicKey 支付宝公钥
     * @param cusPrivateKey   商户私钥
     * @param charset         字符集，如UTF-8, GBK, GB2312
     * @param isEncrypt       是否加密，true-加密  false-不加密
     * @param isSign          是否签名，true-签名  false-不签名
     * @return 加密、签名后xml内容字符串
     * <p>
     * 返回示例：
     * <pay>
     *  <response>密文</response>
     *  <encryption_type>RSA</encryption_type>
     *  <sign>sign</sign>
     *  <sign_type>RSA</sign_type>
     * </pay>
     * </p>
     * @throws PlatformPayException
     */
    public static String encryptAndSign(String bizContent, String payPublicKey,
                                        String cusPrivateKey, String charset, boolean isEncrypt,
                                        boolean isSign) throws PlatformPayException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(charset)) {
            charset = PayConstants.CHARSET_GBK;
        }
        sb.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
        if (isEncrypt) {// 加密
            sb.append("<pay>");
            String encrypted = rsaEncrypt(bizContent, payPublicKey, charset);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>RSA</encryption_type>");
            if (isSign) {
                String sign = rsaSign(encrypted, cusPrivateKey, charset);
                sb.append("<sign>" + sign + "</sign>");
                sb.append("<sign_type>RSA</sign_type>");
            }
            sb.append("</pay>");
        } else if (isSign) {// 不加密，但需要签名
            sb.append("<pay>");
            sb.append("<response>" + bizContent + "</response>");
            String sign = rsaSign(bizContent, cusPrivateKey, charset);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>RSA</sign_type>");
            sb.append("</pay>");
        } else {// 不加密，不加签
            sb.append(bizContent);
        }
        return sb.toString();
    }

    /**
     * 加密并签名<br>
     * <b>目前适用于公众号</b>
     * @param bizContent      待加密、签名内容
     * @param payPublicKey 支付宝公钥
     * @param cusPrivateKey   商户私钥
     * @param charset         字符集，如UTF-8, GBK, GB2312
     * @param isEncrypt       是否加密，true-加密  false-不加密
     * @param isSign          是否签名，true-签名  false-不签名
     * @return 加密、签名后xml内容字符串
     * <p>
     * 返回示例：
     * <pay>
     *  <response>密文</response>
     *  <encryption_type>RSA</encryption_type>
     *  <sign>sign</sign>
     *  <sign_type>RSA</sign_type>
     * </pay>
     * </p>
     * @throws PlatformPayException
     */
    public static String encryptAndSign(String bizContent, String payPublicKey,
                                        String cusPrivateKey, String charset, boolean isEncrypt,
                                        boolean isSign,String signType) throws PlatformPayException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(charset)) {
            charset = PayConstants.CHARSET_GBK;
        }
        sb.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
        if (isEncrypt) {// 加密
            sb.append("<pay>");
            String encrypted = rsaEncrypt(bizContent, payPublicKey, charset);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>RSA</encryption_type>");
            if (isSign) {
                String sign = rsaSign(encrypted, cusPrivateKey, charset, signType);
                sb.append("<sign>" + sign + "</sign>");
                sb.append("<sign_type>");
                sb.append(signType);
                sb.append("</sign_type>");
            }
            sb.append("</pay>");
        } else if (isSign) {// 不加密，但需要签名
            sb.append("<pay>");
            sb.append("<response>" + bizContent + "</response>");
            String sign = rsaSign(bizContent, cusPrivateKey, charset, signType);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>");
            sb.append(signType);
            sb.append("</sign_type>");
            sb.append("</pay>");
        } else {// 不加密，不加签
            sb.append(bizContent);
        }
        return sb.toString();
    }

    /**
     * 公钥加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集，如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws PlatformPayException
     */
    public static String rsaEncrypt(String content, String publicKey, String charset) throws PlatformPayException {
        try {
            PublicKey pubKey = getPublicKeyFromX509(PayConstants.SIGN_TYPE_RSA,
                    new ByteArrayInputStream(publicKey.getBytes()));
            Cipher cipher = Cipher.getInstance(PayConstants.SIGN_TYPE_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = StringUtils.isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.encodeBase64(out.toByteArray());
            out.close();

            return StringUtils.isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new PlatformPayException("EncryptContent = " + content + ",charset = " + charset, e);
        }
    }

    /**
     * 私钥解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @param charset    字符集，如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws PlatformPayException
     */
    public static String rsaDecrypt(String content, String privateKey, String charset) throws PlatformPayException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(PayConstants.SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));
            Cipher cipher = Cipher.getInstance(PayConstants.SIGN_TYPE_RSA);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            byte[] encryptedData = StringUtils.isEmpty(charset)
                    ? Base64.decodeBase64(content.getBytes())
                    : Base64.decodeBase64(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return StringUtils.isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new PlatformPayException("EncodeContent = " + content + ",charset = " + charset, e);
        }
    }


}

